#ifndef __TUPLE_HASH_H_INCL__
#define __TUPLE_HASH_H_INCL__

#include <tuple>
namespace std{
	namespace
	{

		template <class T>
		inline void hash_combine(std::size_t& seed, T const& v)
		{
			// code from boost <boost/functional/hash/hash.hpp>
			seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
		}

		template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
		struct HashValueImpl
		{
		  static void apply(size_t& seed, Tuple const& tuple)
		  {
			HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
			boost::hash_combine(seed, get<Index>(tuple));
		  }
		};

		template <class Tuple>
		struct HashValueImpl<Tuple,0>
		{
		  static void apply(size_t& seed, Tuple const& tuple)
		  {
			boost::hash_combine(seed, get<0>(tuple));
		  }
		};
	}

	template <typename ... TT>
    struct hash<std::tuple<TT...>> 
    {
		size_t
		operator()(std::tuple<TT...> const& tt) const
		{                                              
			size_t seed = 0;                             
			HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
			return seed;                                 
		}                                              
	
    };
}


#endif // __TUPLE_HASH_H_INCL__

